﻿/***  File Header  ************************************************************/
/**
* @file P4th.cpp
*
* PICO FORTHインタープリタ
* @author	shozo fukuda
* @date		作成 Tue Oct 11 19:52:03 2005
* @date		修正 $Date: 06/04/14 10:08 $
* System	Generic <br>
*
*******************************************************************************/

/*******************************************************************************
* IMPORTS:
*******************************************************************************/
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

#include <ctype.h>
#include "Dic.h"
#include "P4th.h"	/* 呼出用 */

/*******************************************************************************
* CONSTANT:
*******************************************************************************/

/*******************************************************************************
* TYPE:
*******************************************************************************/

/*******************************************************************************
* MACRO:
*******************************************************************************/

/*******************************************************************************
* GLOBAL VARIABLE:
*******************************************************************************/

/***  Module Header  ******************************************************}}}*/
/**
* インスタンス
* @par 解説
*   グローバル・インスタンスを返します。
**/
/**************************************************************************{{{*/
P4th* P4th::Instance(
TxIO* io)						///< (r) 入出力チャネル
{
	static P4th _obj;

	_obj.AttachIO(io);
	return &_obj;
}

/***  Module Header  **********************************************************/
/**
* コンストラクタ
* @par 解説
*   インスタンスを構築します。
* @see
*
*******************************************************************************/
P4th::P4th()
: iText(&mTextBuff[MAX_BACK_TEXT])
{
	iState   = INTERPRET;
	iCapital = 1;

	/* スタックの初期化 */
	mDSize = MAX_DSTACK;
	mSP    = 0;

	mRSize = MAX_RSTACK;
	mRP    = 0;

	/* 入出力チァネルの初期化 */												
	mIO = 0;
	
	/* コード領域の初期化 */
	for (mDP = 0; mDP < _CodeFence; mDP++) {
		mCode[mDP] = _Code[mDP];
	}
	iCurrent = FENCE;

	/* 名前領域の初期化 */
	for (mNP = 0; mNP < _NameFence; mNP++) {
		mName[mNP] = _Name[mNP];
	}

	/* テキストバッファ関連の初期化 */
	memset(iText, 0, MAX_TAKE_TEXT);		// 入力テキストを空に初期化する

	mCP = iText;		// カーソルの初期化
									/*+MEMO:shoz:06/02/13:入力テキストを空に初期化したので、最初に
									        読み出される文字は終端文字'\0' */
}

/***  Module Header  ******************************************************}}}*/
/**
* P4thマシンのリセット
* @par 解説
*   P4thマシンの入力制御、スタックを初期化します。
**/
/**************************************************************************{{{*/
void P4th::Reset()
{
	/* テキストバッファ関連の初期化 */
	memset(iText, 0, MAX_TAKE_TEXT);		// 入力テキストを空に初期化する

	mCP = iText;		// カーソルの初期化
									/*+MEMO:shoz:06/02/13:入力テキストを空に初期化したので、最初に
									        読み出される文字は終端文字'\0' */
}

/***  Module Header  ******************************************************}}}*/
/**
* P4thインタプリタ・シーケンス
* @par 解説
*   テキストを1行読み込み解釈・実行します。
**/
/**************************************************************************{{{*/
void P4th::REP()
{
	if (ReadLine()) {
		Eval();
		Printf(" ok\n>");
	}
}

/***  Module Header  ******************************************************}}}*/
/**
* P4thテキストインタプリタ
* @par 解説
*   テキストバッファに入力されたテキストを解釈・実行します。
**/
/**************************************************************************{{{*/
void P4th::Eval()
{
	mCP = iText;
	while (ReadWord(mSym)) {
		Code pcode = Find(mSym);

		if (iState == INTERPRET || IsImmediate(pcode)) {
			// インタープリット
			iIP = 0;
			Call(pcode);

			while (iIP > 0) {
				pcode = mCode[iIP++];
				Call(pcode);
			}

		} else if (iState == COMP_CODE || iState == COMP_SELF) {
			// コンパイル: CODEフェーズ
			Build(pcode);
		}
	}
}

/***  Module Header  ******************************************************}}}*/
/**
* セルフコンパイル開始
* @par 解説
*   セルフコンパイル開始の処理を行ないます。
**/
/**************************************************************************{{{*/
void P4th::BegSelf()
{
	if (iState == INTERPRET) {
		iState = COMP_SELF;

		mNPX = mNP;
		mDPX = mDP;
		mCSP = mSP;

		mDP = EXAM;
	}
}

/***  Module Header  ******************************************************}}}*/
/**
* セルフコンパイル終了
* @par 解説
*   セルフコンパイル終了の処理を行ないます。
**/
/**************************************************************************{{{*/
void P4th::EndSelf()
{
	if (iState == COMP_SELF && mSP == mCSP) {
		Build(P_EXIT);

		mNP = mNPX;
		mDP = mDPX;
	
		RPush(iIP);
		iIP = EXAM;

		iState = COMP_FINISH;
	}
}

/***  Module Header  ******************************************************}}}*/
/**
* 未定義ワードの処理
* @par 解説
*   未定義ワードを数値または組み込み定数として解釈を試みます。数値または組み込み
*   定数として解釈できない場合はエラーメッセージを出力します。
**/
/**************************************************************************{{{*/
void P4th::Unknown()
{
	long val;
	
	if (ConvNum(val)) {
		Push(val);
		Literal();

	} else if (FindConst(val)) {
		Push(val);
		Literal();

	} else {
		Printf("未知のワード\n");
	}
}

/***  Module Header  ******************************************************}}}*/
/**
* 数値リテラルのコンパイル
* @par 解説
*   数値リテラルをコンパイルし、コードを生成します。
**/
/**************************************************************************{{{*/
void P4th::Literal()
{
	if (iState != INTERPRET) {
		Magic val;
		val.D = Pop();

		Build(P_LIT);
		Build(val.C[0]);
		Build(val.C[1]);
	}
}

/***  Module Header  ******************************************************}}}*/
/**
* 文字列->数値変換
* @par 解説
*   シンボルバッファmSymの文字列を数値に変換し、引数valに返します。
*
* @retval true  数値変換成功。
* @retval false 数値変換失敗。
**/
/**************************************************************************{{{*/
bool P4th::ConvNum(
long& val)
{
	long sign = 1;
	long len  = mSym[0];
	long i    = 1;

	val = 0;

	if      (mSym[i] == '+') { sign =  1; i++; }
	else if (mSym[i] == '-') { sign = -1; i++; }

	if (mSym[i] == '0') {
		i++;
		
		if (mSym[i] == 'x' || mSym[i] == 'X') {
			// 16進数
			i++;

			for (; i <= len; i++) {
				if (isdigit(mSym[i])) {
					val = 16*val + (mSym[i] - '0');

				} else if (mSym[i] >= 'A' && mSym[i] <= 'F') {
					val = 16*val + (mSym[i] - 'A') + 10;

				} else if (mSym[i] >= 'a' && mSym[i] <= 'f') {
					val = 16*val + (mSym[i] - 'a') + 10;

				} else return false;
			}

		} else {
			// 0 または 8進数
			for (; i <= len; i++) {	
				if (mSym[i] >= '0' && mSym[i] <= '7') {
					val = 8*val + (mSym[i] - '0');

				} else return false;
			}
		}

	} else if (isdigit(mSym[i])) {
		// 10進数
		for (; i <= len; i++) {
			if (isdigit(mSym[i])) {
				val = 10*val + (mSym[i] - '0');

			} else return false;
		}

	} else {
		return false;
	}
	
	val *= sign;
	return true;
}

/***  Module Header  ******************************************************}}}*/
/**
* ワード定義
* @par 解説
*   辞書に新たなワードエントリを確保し、ワード名と２次ワード実行ワードS_DOCOLを
*   埋め込みます。また、FORTHステートをコンパイルステートに設定します。
**/
/**************************************************************************{{{*/
void P4th::Colon()
{
	long n;

	Code word = Create();

	n = ReadWord(mSym);

	memcpy(Name(word), mSym, n+1);
	mNP += n+1;
	
	mCode[W2CFA(word)] = S_DOCOL;
	
	iState = COMP_CODE;
}

/***  Module Header  ******************************************************}}}*/
/**
* 定数定義
* @par 解説
*   辞書に新たなワードエントリを確保し、定数名、定数実行ワードS_DOCONSTと定数値
*   を埋め込みます。
**/
/**************************************************************************{{{*/
void P4th::Constant()
{
	long n;

	Word word = Create();
	
	n = ReadWord(mSym);
	memcpy(Name(word), mSym, n+1);
	mNP += n+1;
	
	mCode[W2CFA(word)] = S_DOCONST;
	
	Magic val;
	val.D = Pop();
	Build(val.C[0]);
	Build(val.C[1]);
}

/***  Module Header  ******************************************************}}}*/
/**
* 定数実行ワード
* @par 解説
*   定義済み定数をスタックに積みます。さらに、FORTHステートがコンパイルステート
*   であれば、スタックに積んだ定数をコンパイルします。
**/
/**************************************************************************{{{*/
void P4th::DoConst()
{
	Magic val;
	val.C[0] = mCode[iW];
	val.C[1] = mCode[iW+1];
	Push(val.D);
	Literal();
}

/***  Module Header  ******************************************************}}}*/
/**
* FORTH変数定義
* @par 解説
*   FORTH変数を定義します。<br>
*   (1)引き続くテキストをワード名としてワードヘッダを作成する。<br>
*   (2)実行コードにS_DOVARを埋め込む。<br>
*   (3)パラメタフィールドを32bit分確保し、0クリアする。<br>
**/
/**************************************************************************{{{*/
void P4th::Variable()
{
	long n;

	Word word = Create();
	
	n = ReadWord(mSym);
	memcpy(Name(word), mSym, n+1);
	mNP += n+1;

	mCode[W2CFA(word)] = S_DOVAR;
	
	Build(0);
	Build(0);
}

/***  Module Header  ******************************************************}}}*/
/**
* 変数実行ワード
* @par 解説
*   定義済み変数の値をスタックに積みます。
**/
/**************************************************************************{{{*/
void P4th::DoVar()
{
	Push(iW);
	Literal();
}

/***  Module Header  ******************************************************}}}*/
/**
* 1行入力
* @par 解説
*   テキストバッファに1行入力します。
*
* @retval 0    　入力文字が無かった。
* @retval その他 入力行。
**/
/**************************************************************************{{{*/
char* P4th::ReadLine()
{
	return mIO->GetS(iText, 0);
}

/***  Module Header  ******************************************************}}}*/
/**
* 1文字出力
* @par 解説
*   出力デバイスに文字cを印字します。
**/
/**************************************************************************{{{*/
void P4th::PutC(
char c)							///< (r) 印字文字
{	
	mIO->PutC(c);
}

/***  Module Header  ******************************************************}}}*/
/**
* 1行出力
* @par 解説
*   出力デバイスに文字列sを印字します。
**/
/**************************************************************************{{{*/
void P4th::PutS(
char* s)						///< (r) 印字文字列
{
	while (*s) {
		PutC(*s++);
	}
}

/***  Module Header  ******************************************************}}}*/
/**
* 書式指定付きメッセージ出力
* @par 解説
*   書式fmtにしたがって可変個の引数を変換し、その結果文字列を出力デバイスに印字
*   します。
**/
/**************************************************************************{{{*/
void P4th::Printf(
char* fmt,
...)
{
	va_list args;
	va_start(args, fmt);
	vsprintf(mMessage, fmt, args);
	va_end(args);

	PutS(mMessage);	
}

/***  Module Header  ******************************************************}}}*/
/**
* バージョン出力
* @par 解説
*   出力デバイスにP4thのバージョンを印字します。
**/
/**************************************************************************{{{*/
void P4th::Version()
{
#define VER_MAJOR 2
#define VER_MINOR 0
	Printf("P4th: Pico FORTH interpreter ver %02d.%02d\n", VER_MAJOR, VER_MINOR);
}

/***  Module Header  ******************************************************}}}*/
/**
* ワード一覧印字
* @par 解説
*   定義済みワードの一覧を印字します。
**/
/**************************************************************************{{{*/
void P4th::DumpNew()
{
	Code code = iCurrent;
	
	while (code < mDP) {
		printf("%3d\n", mCode[code++]);
	}
}

/* end of P4th.cpp */

